'''
copyright: Copyright (C) 2015-2024, Wazuh Inc.

           Created by Wazuh, Inc. <info@wazuh.com>.

           This program is free software; you can redistribute it and/or modify it under the terms of GPLv2

type: integration

brief: Wazuh is able to detect vulnerabilities in the applications installed in agents using the Vulnerability Detector
       module. This software audit is performed through the integration of vulnerability feeds indexed by Redhat,
       Canonical, Debian, Amazon Linux and NVD Database.

components:
    - vulnerability_detector

suite: scan_types

targets:
    - manager

daemons:
    - wazuh-modulesd

os_platform:
    - linux

os_version:
    - Arch Linux
    - Amazon Linux 2
    - Amazon Linux 1
    - CentOS 8
    - CentOS 7
    - Debian Buster
    - Red Hat 8
    - Ubuntu Focal
    - Ubuntu Bionic

references:
    - https://documentation.wazuh.com/current/user-manual/capabilities/vulnerability-detection/index.html

tags:
    - vulnerability_detector
    - scan_types
'''
import pytest
from pathlib import Path

from wazuh_testing.constants.daemons import ANALYSISD_DAEMON, MODULES_DAEMON, SYSCHECK_DAEMON
from wazuh_testing.utils.configuration import (get_test_cases_data, load_configuration_template,
                                               update_configuration_template)
from wazuh_testing.modules.modulesd.vulnerability_detector import patterns as cb
from wazuh_testing.modules.modulesd.configuration import MODULESD_DEBUG
from wazuh_testing.modules.monitord.configuration import MONITORD_ROTATE_LOG
from wazuh_testing.utils.mocking import VULNERABLE_PACKAGES
from test_vulnerability_detector import utils as evm
from . import (TEST_CASES_PATH, CONFIGURATIONS_PATH, custom_rhel_oval_feed_path,
               custom_rhel_json_feed_path, custom_nvd_json_feed_path)


pytest.skip("The tests will be deprecated, they test the old Vulnerability Detector.", allow_module_level=True)

# Variables
local_internal_options = {MODULESD_DEBUG: '2', MONITORD_ROTATE_LOG: '0'}
daemons_handler_configuration = {'daemons': [ANALYSISD_DAEMON, MODULES_DAEMON, SYSCHECK_DAEMON]}
pytestmark = [pytest.mark.server]

# Configuration and cases data
configurations_path = Path(CONFIGURATIONS_PATH, 'configuration_baseline_scan.yaml')
t1_cases_path = Path(TEST_CASES_PATH, 'cases_baseline_scan_start.yaml')
t2_cases_path = Path(TEST_CASES_PATH, 'cases_baseline_scan_alert.yaml')

# test_baseline_scan_start configurations
t1_configuration_parameters, t1_configuration_metadata, t1_case_ids = get_test_cases_data(t1_cases_path)
t1_configurations = load_configuration_template(configurations_path, t1_configuration_parameters,
                                                t1_configuration_metadata)
t1_systems = [metadata['system'] for metadata in t1_configuration_metadata]

# test_baseline_scan_no_alert configurations
t2_configuration_parameters, t2_configuration_metadata, t2_case_ids = get_test_cases_data(t2_cases_path)
t2_configurations = load_configuration_template(configurations_path, t2_configuration_parameters,
                                                t2_configuration_metadata)
t2_systems = [metadata['system'] for metadata in t2_configuration_metadata]

# Set offline custom feeds configuration
t1_configurations = update_configuration_template(
    t1_configurations,  ['CUSTOM_REDHAT_OVAL_FEED', 'CUSTOM_REDHAT_JSON_FEED', 'CUSTOM_NVD_JSON_FEED'],
    [custom_rhel_oval_feed_path, custom_rhel_json_feed_path, custom_nvd_json_feed_path])
t2_configurations = update_configuration_template(
    t2_configurations,  ['CUSTOM_REDHAT_OVAL_FEED', 'CUSTOM_REDHAT_JSON_FEED', 'CUSTOM_NVD_JSON_FEED'],
    [custom_rhel_oval_feed_path, custom_rhel_json_feed_path, custom_nvd_json_feed_path])


@pytest.mark.tier(level=0)
@pytest.mark.parametrize('test_configuration, test_metadata, agent_system',
                         zip(t1_configurations, t1_configuration_metadata, t1_systems), ids=t1_case_ids)
def test_baseline_scan_start(test_configuration, test_metadata, agent_system, set_wazuh_configuration,
                             configure_local_internal_options, truncate_monitored_files, clean_cve_tables,
                             prepare_baseline_scan_with_vuln_packages, daemons_handler):
    '''
    description: Check that the baseline scan starts.

    test_phases:
        - Setup:
            - Mock an agent with vulnerable packages.
            - Update sync_info packages data for that mocked agent.
            - Force a baseline scan setting the last full scan DB data.
            - Set a custom Wazuh configuration, with custom feeds for OVAL and NVD.
            - Restart wazuh-modulesd.
        - Test:
            - Check a baseline scan has started.
        - Teardown:
            - Truncate log files
            - Clean CVE tables
            - Remove mocked agent
            - Restore configuration files
            - Restart wazuh-modulesd

    wazuh_min_version: 4.3.0

    tier: 1

    parameters:
        - test_configuration:
            type: dict
            brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture.
        - test_metadata:
            type: dict
            brief: Wazuh configuration metadata
        - agent_system:
            type: str
            brief: System to set to the mocked agent.
        - set_wazuh_configuration:
            type: fixture
            brief: Set the wazuh configuration according to the configuration data.
        - configure_local_internal_options:
            type: fixture
            brief: Set local_internal_options configuration.
        - truncate_monitored_files:
            type: fixture
            brief: Truncate all the log files and json alerts files before and after the test execution.
        - clean_cve_tables:
            type: fixture
            brief: Clean all CVE tables.
        - prepare_baseline_scan_with_vuln_packages:
            type: fixture
            brief: Setup the initial test state.
        - daemons_handler:
            type: fixture
            brief: Restart the wazuh-modulesd daemon.

    assertions:
        - Check that the baseline scan log appears.

    input_description:
        - The `configuration_baseline_scan.yaml` file provides the module configuration for this test.
        - The `cases_baseline_scan_start` file provides the test cases.

    expected_output:
        - f"A baseline scan will be run on agent '{agent_id}'"
    '''
    agent_id = prepare_baseline_scan_with_vuln_packages

    # Check (in log) that the baseline scan has been launched
    log_present = evm.check_baseline_scan_start(agent_id)
    assert log_present is not None, f"No Baseline scan start log found."


@pytest.mark.tier(level=1)
@pytest.mark.parametrize('test_configuration, test_metadata, agent_system',
                         zip(t2_configurations, t2_configuration_metadata, t2_systems), ids=t2_case_ids)
def test_baseline_scan_alert(test_configuration, test_metadata, agent_system, set_wazuh_configuration,
                             configure_local_internal_options, truncate_monitored_files, clean_cve_tables,
                             prepare_baseline_scan_with_vuln_packages, daemons_handler):
    '''
    description: Check that the baseline scan detects vulnerabilities, and reports them as alerts.

    test_phases:
        - Setup:
            - Mock an agent with vulnerable packages.
            - Update sync_info packages data for that mocked agent.
            - Force a baseline scan setting the last full scan DB data.
            - Set a custom Wazuh configuration, with custom feeds for OVAL and NVD.
            - Restart wazuh-modulesd.
        - Test:
            - Wait for a baseline scan.
            - Check that the vulnerability has been detected.
            - Check that vulnerability alert has been generated.
        - Teardown:
            - Truncate log files
            - Clean CVE tables
            - Remove mocked agent
            - Restore configuration files
            - Restart wazuh-modulesd

    wazuh_min_version: 4.3.0

    tier: 1

    parameters:
        - test_configuration:
            type: dict
            brief: Wazuh configuration data. Needed for set_wazuh_configuration fixture.
        - test_metadata:
            type: dict
            brief: Wazuh configuration metadata
        - agent_system:
            type: str
            brief: System to set to the mocked agent.
        - set_wazuh_configuration:
            type: fixture
            brief: Set the wazuh configuration according to the configuration data.
        - configure_local_internal_options:
            type: fixture
            brief: Set local_internal_options configuration.
        - truncate_monitored_files:
            type: fixture
            brief: Truncate all the log files and json alerts files before and after the test execution.
        - clean_cve_tables:
            type: fixture
            brief: Clean all CVE tables.
        - prepare_baseline_scan_with_vuln_packages:
            type: fixture
            brief: Setup the initial test state.
        - daemons_handler:
            type: fixture
            brief: Restart the wazuh-modulesd daemon.

    assertions:
        - Check that the vulnerability is detected.
        - Check that the vulnerability alert is generated.

    input_description:
        - The `configuration_baseline_scan.yaml` file provides the module configuration for this test.
        - The `cases_baseline_scan_alert` file provides the test cases.

    expected_output:
        - f"The '{package}' package .* from agent '{agent_id}' is vulnerable to '{cve}'"
        - f".*"agent":."id":"{agent_id}".*{cve} affects {package}"
    '''
    agent_id = prepare_baseline_scan_with_vuln_packages
    package = VULNERABLE_PACKAGES[0]['name']
    cve = VULNERABLE_PACKAGES[0]['cveid']

    # Check (in log) that the baseline scan has been launched
    log_present = evm.check_baseline_scan_start(agent_id)
    assert log_present is not None, f"No Baseline scan start log found."

    # Check that the vulnerability from first package is detected
    log_present = evm.check_cve_affects_package_log(agent_id, package, cve)
    assert log_present is not None, f"Expected 'package {package} is vulnerable to cve' log not found"

    # Check that there is vulnerability alert (baseline scan generate alerts)
    alert_present = evm.check_cve_affects_package_alert(agent_id, package, cve)
    assert alert_present is not None, f"Expected '{cve} affects {package}' alert not found"
